package com.example.staticdemo.config;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Configuration
public class ThreadPoolService {

//    @Value("${threadPool.coreSize}")
//    private Integer coreSize;

    @Bean
    public ThreadPoolExecutor insertVoicePool() {
//        核心线程：
//        CPU密集型：核心线程数=CPU核心数(或 核心线程数=CPU核心数+1)。
//        I/O密集型：核心线程数=2*CPU核心数（或 核心线程数=CPU核心数/（1-阻塞系数))。
        int coreSize = Runtime.getRuntime().availableProcessors() * 2; //获取当前机器的核数, 不一定准确 请根据实际场景
        // corePoolSize 是线程池中的一个最小的线程数量，即使这些线程处理空闲状态，他们也不会被销毁，除非设置了allowCoreThreadTimeOut
        // 设置allowCoreThreadTimeout=true（默认false）时，核心线程会超时关闭
        return new ThreadPoolExecutor(coreSize,
                coreSize,
                // 当线程空闲时间达到keepAliveTime值时,多余的线程会被销毁直到只剩下corePoolSize个线程为止
                10L,
                // keepAliveTime的计量单位
                TimeUnit.SECONDS,
                // 链表的无界阻塞队列，不设置容量则默认使用 Integer.Max_VALUE 作为容量 （无界队列），该队列的吞吐量高于 ArrayBlockingQueue
                // 由于该队列的近似无界性，当线程池中线程数量达到corePoolSize后，再有新任务进来，会一直存入该队列，而不会去创建新线程直到maxPoolSize，因此使用该工作队列时，参数maxPoolSize其实是不起作用的
                new LinkedBlockingQueue<>(2000),
                new ThreadFactoryBuilder()
                        .setNamePrefix("insertVoice-")
                        .setUncaughtExceptionHandler((thread, e) -> log.error("insertVoicePool {} exception {}", thread, e))
                        .build(),
//                AbortPolicy（默认）：丢弃任务并抛出 RejectedExecutionException 异常。
//                CallerRunsPolicy：由调用线程处理该任务。
//                DiscardPolicy：丢弃任务，但是不抛出异常。可以配合这种模式进行自定义的处理方式。
//                DiscardOldestPolicy：丢弃队列最早的未处理任务，然后重新尝试执行任务。
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

}
